package com.liyunc.demo.bundle.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

/**
 * @author liyuncong
 * @version 1.0
 * @file OAuth2Configuration
 * @brief OAuth2Configuration
 * @details OAuth2Configuration
 * @date 2022/4/1
 *
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                        NAME               DESCRIPTION
 * 2022/4/1                     liyuncong          Created
 */
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    private AuthenticationManager authenticationManager;

    private static final String CLIENT_ID = "cms";
    private static final String SECRET_CHAR_SEQUENCE = "{noop}secret";
    private static final String SCOPE_READ = "read";
    private static final String SCOPE_WRITE = "write";
    private static final String TRUST = "trust";
    private static final String USER ="user";
    private static final String ALL = "all";
    private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60;
    private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60;
    // 密码模式授权模式
    private static final String GRANT_TYPE_PASSWORD = "password";
    //授权码模式
    private static final String AUTHORIZATION_CODE = "authorization_code";
    //refresh token模式
    private static final String REFRESH_TOKEN = "refresh_token";
    //简化授权模式
    private static final String IMPLICIT = "implicit";
    //指定哪些资源是需要授权验证的
    private static final String RESOURCE_ID = "resource_id";


    /**
     * 配置客户端，可存在内存和数据库中.
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
            // 使用内存存储
            .inMemory()
            //标记客户端id
            .withClient(CLIENT_ID)
            //客户端安全码
            .secret(SECRET_CHAR_SEQUENCE)
            //为true 直接自动授权成功返回code
            .autoApprove(true)
            //重定向uri
            .redirectUris("http://127.0.0.1:8080/api/v1/login")
            //允许授权范围
            .scopes(ALL)
            //token 时间秒
            .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
            //刷新token 时间 秒
            .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)
            //允许授权类型
            .authorizedGrantTypes(GRANT_TYPE_PASSWORD , AUTHORIZATION_CODE , REFRESH_TOKEN , IMPLICIT);
    }

    /**
     * 配置授权服务器的安全性，令牌端点的安全约束.
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            // 开启 /oauth/check_token
            .tokenKeyAccess("permitAll()")
            // 开启 /oauth/token_key
            .checkTokenAccess("isAuthenticated()")
            // 允许表单认证
            // 如果配置，且url中有client_id和client_secret的，则走 ClientCredentialsTokenEndpointFilter
            // 如果没有配置，但是url中没有client_id和client_secret的，走basic认证保护
            .allowFormAuthenticationForClients();
    }


}
